/*
 * FreeModbus Libary: user callback functions and buffer define in master mode
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $
 */
#include <math.h>
#include <stdio.h>
#include "calc.h"
#include "fifo.h"
#include "global_var.h"
#include "reg_map_check.h"
#include "user_mb_app.h"
#define MBM_FIFO_DEPTH M_REG_HOLDING_NREGS
fifo8_cb_td       mbm_data_fifo;
extern sys_reg_st g_sys;  // global parameter declairation
#define MBM_RESPONSE_DELAY 100
#define MBM_QUEST_DELAY    100
#define MBM_ERR_NUM        5

#define MBM_DISCRETE_DEV_CNT 1
/*************************************************IPM ************************************/
#define IPM_READ_CNT        4
#define IPM_WRITE_CNT       1
#define IPM_FREQUENCY_RATIO 0.00106813
#define IPM_POWER_RATIO     0.4
#define IPM_ALL_RATIO       0.1
mbm_read_dev_reg IPM_read_reg[IPM_READ_CNT] = {
    {IPM_Ux_Addr,    IPM_Ux_Num,    &g_sys.status.mbm.IPM.IPM.Ux[0], 0                                   },
    {IPM_Wh_Addr,    IPM_Wh_Num,    &g_sys.status.mbm.IPM.P_Wh_H,    IPM_Ux_Num                          },
    {IPM_PT_Addr,    IPM_PT_Num,    &g_sys.status.mbm.IPM.PT,        IPM_Ux_Num + IPM_Wh_Num             },
    {IPM_DP_CT_Addr, IPM_DP_CT_Num, &g_sys.status.mbm.IPM.DP_CT,     IPM_Ux_Num + IPM_Wh_Num + IPM_PT_Num},
};

/*****************************************************************************************/

#define UPS_WRITE_CNT 0
const mbm_read_st mbm_read_table[MBM_DISCRETE_DEV_CNT] = {
    {MBM_DEV_IPM_ADDR, IPM_READ_CNT, IPM_read_reg, IPM_WRITE_CNT, NULL}, // IPM;
};

static uint16_t mbm_reg_update(mbm_dev_st *mbm_dev_inst, UCHAR ucMB_Number);
static void     mbm_fsm_init(mbm_dev_st *mbm_dev_inst);
static void     mbm_fsm_update(sys_reg_st *gds_ptr, mbm_dev_st *mbm_dev_inst, UCHAR ucMB_Number);

/*-----------------------Master mode use these variables----------------------*/
// Master mode:HoldingRegister variables
static uint16_t   usMRegHoldStart = M_REG_HOLDING_START;
static uint16_t   usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
static mbm_dev_st mbm_dev_inst[MB_MASTER_NUM];
/******************************MB_MASTER_00****************************************/

/******************************MB_MASTER_01****************************************/
#define MBM_FIFO_DEPTH_01 M_REG_HOLDING_NREGS_01
fifo8_cb_td mbm_data_fifo_01;

uint16_t AC_PowerON = 0;

static uint16_t firstFlag = 0;
/*************************************************AC ************************************/
#define AC_READ_CNT  4
#define AC_WRITE_CNT 11
mbm_read_dev_reg AC_read_reg[AC_READ_CNT] = {
    {30001, 0x0a, &g_sys.status.mbm.AC.suctionTemp,         0                 },
    {30021, 0x04, &g_sys.status.mbm.AC.alarmHighTemp,       0x0a              },
    {30027, 0x06, &g_sys.status.mbm.AC.TempSet0,            0x0a + 0x04       },
    {30061, 0x06, &g_sys.status.mbm.AC.insideFanPercentage, 0x0a + 0x04 + 0x06},
};
mbm_write_dev_reg AC_write_reg[AC_WRITE_CNT] = {
    {30021, 60, &g_sys.config.mbm_Conf.AC.alarmHighTemp.Data,       &g_sys.config.mbm_Conf.AC.alarmHighTemp.Flag,       &g_sys.status.mbm.AC.alarmHighTemp,       MB_WRITE_SINGLE },
    {30022, 61, &g_sys.config.mbm_Conf.AC.alarmLowTemp.Data,        &g_sys.config.mbm_Conf.AC.alarmLowTemp.Flag,        &g_sys.status.mbm.AC.alarmLowTemp,        MB_WRITE_SINGLE },
    {30023, 62, &g_sys.config.mbm_Conf.AC.alarmHighHumidity.Data,   &g_sys.config.mbm_Conf.AC.alarmHighHumidity.Flag,   &g_sys.status.mbm.AC.alarmHighHumidity,   MB_WRITE_SINGLE },
    {30026, 63, &g_sys.config.mbm_Conf.AC.alarmLowHumidity.Data,    &g_sys.config.mbm_Conf.AC.alarmLowHumidity.Flag,    &g_sys.status.mbm.AC.alarmLowHumidity,    MB_WRITE_SINGLE },
    {30027, 64, &g_sys.config.mbm_Conf.AC.TempSet0.Data,            &g_sys.config.mbm_Conf.AC.TempSet0.Flag,            &g_sys.status.mbm.AC.TempSet0,            MB_WRITE_SINGLE },
    {30028, 65, &g_sys.config.mbm_Conf.AC.TempRange0.Data,          &g_sys.config.mbm_Conf.AC.TempRange0.Flag,          &g_sys.status.mbm.AC.TempRange0,          MB_WRITE_SINGLE },
    {30029, 66, &g_sys.config.mbm_Conf.AC.tempStagnationZone0.Data, &g_sys.config.mbm_Conf.AC.tempStagnationZone0.Flag, &g_sys.status.mbm.AC.tempStagnationZone0, MB_WRITE_SINGLE },
    {30030, 67, &g_sys.config.mbm_Conf.AC.TempSet1.Data,            &g_sys.config.mbm_Conf.AC.TempSet1.Flag,            &g_sys.status.mbm.AC.TempSet1,            MB_WRITE_SINGLE },
    {30031, 68, &g_sys.config.mbm_Conf.AC.TempRange1.Data,          &g_sys.config.mbm_Conf.AC.TempRange1.Flag,          &g_sys.status.mbm.AC.TempRange1,          MB_WRITE_SINGLE },
    {30032, 69, &g_sys.config.mbm_Conf.AC.tempStagnationZone1.Data, &g_sys.config.mbm_Conf.AC.tempStagnationZone1.Flag, &g_sys.status.mbm.AC.tempStagnationZone1, MB_WRITE_SINGLE },
    {10042, 70, &g_sys.config.mbm_Conf.AC.powerOn.Data,             &g_sys.config.mbm_Conf.AC.powerOn.Flag,             &AC_PowerON,                              MB_WR_SINGLE_BIT},
};

#define MBM_DISCRETE_DEV_CNT_1 1
/*****************************************************************************************/
const mbm_read_st mbm_read_table_01[MBM_DISCRETE_DEV_CNT_1] = {
  //   mbmaddr      read_reg_cnt   read_pt    write_reg_cnt   write_pt
    {MBM_DEV_AC_ADDR, AC_READ_CNT, AC_read_reg, AC_WRITE_CNT, AC_write_reg}, // AC;
};

static uint16_t usMRegHoldBuf_01[MB_MASTER_SLAVE_NUM_01][M_REG_HOLDING_NREGS_01];
/******************************MB_MASTER_01****************************************/

/**
 * @brief  modbus master poll thread
 * @param  none
 * @retval none
 **/

//  mbm_send _data

static void mbm_fifo_init(UCHAR ucMB_Number)
{
    uint8_t block_size;

    block_size = sizeof(mbm_data_st);
    switch (ucMB_Number) {
        case MB_MASTER_0:
            if (mbm_data_fifo.buffer_ptr) {
                fifo8_reset(&mbm_data_fifo);
            } else {
                fifo8_init(&mbm_data_fifo, block_size, MBM_FIFO_DEPTH);
            }
            break;
        case MB_MASTER_1:
            if (mbm_data_fifo_01.buffer_ptr) {
                fifo8_reset(&mbm_data_fifo_01);
            } else {
                fifo8_init(&mbm_data_fifo_01, block_size, MBM_FIFO_DEPTH);
            }
            break;
        default:
            break;
    }
}

void modbus_master_thread_entry(void *parameter)
{
    eMBErrorCode eStatus = MB_ENOERR;
    rt_thread_delay(MODBUS_MASTER_THREAD_DELAY);
    eStatus = eMBMasterInit(MB_RTU, UPORT_MBMASTER, 9600, MB_PAR_NONE, MB_MASTER_0);
    if (eStatus != MB_ENOERR) {
        rt_kprintf("MBM init fail\n");
    }
    eStatus = eMBMasterEnable(MB_MASTER_0);
    if (eStatus != MB_ENOERR) {
        rt_kprintf("MBM enable fail\n");
    }
    // init mbm_fifo
    mbm_fifo_init(MB_MASTER_0);
    while (1) {
        eStatus = eMBMasterPoll();
        if (eStatus != MB_ENOERR) {
            rt_kprintf("MBM poll err!\n");
        }
        rt_thread_delay(10);
    }
}

void mbm_fsm_thread_entry(void *parameter)
{
    extern sys_reg_st g_sys;
    rt_thread_delay(MBM_FSM_THREAD_DELAY);
    mbm_fsm_init(&mbm_dev_inst[MB_MASTER_0]);  // initialize local modbus master register set
    rt_kprintf("mbm_fsm_thread_entry\n");
    while (1) {
        // update modbus slave components into local modbus master register
        mbm_fsm_update(&g_sys, &mbm_dev_inst[MB_MASTER_0], MB_MASTER_0);
        rt_thread_delay(1000);
    }
}

void modbus_master_thread_entry_01(void *parameter)
{
    eMBErrorCode eStatus = MB_ENOERR;
    rt_thread_delay(MODBUS_MASTER_THREAD_DELAY_01);
    eStatus = eMBMasterInit(MB_RTU, UPORT_MBMASTER, 9600, MB_PAR_NONE, MB_MASTER_1);
    if (eStatus != MB_ENOERR) {
        rt_kprintf("MBM init fail\n");
    }
    eStatus = eMBMasterEnable(MB_MASTER_1);
    if (eStatus != MB_ENOERR) {
        rt_kprintf("MBM enable fail\n");
    }
    // init mbm_fifo
    mbm_fifo_init(MB_MASTER_1);
    rt_kprintf("modbus_master_thread_entry_01\n");
    while (1) {
        eStatus = eMBMasterPoll_01();
        if (eStatus != MB_ENOERR) {
            rt_kprintf("MBM poll err!\n");
        }
        rt_thread_delay(10);
    }
}

void mbm_fsm_thread_entry_01(void *parameter)
{
    extern sys_reg_st g_sys;
    rt_thread_delay(MBM_FSM_THREAD_DELAY_01);
    mbm_fsm_init(&mbm_dev_inst[MB_MASTER_1]);  // initialize local modbus master register set
    // AC_Conf_Write(0, 0);
    rt_kprintf("mbm_fsm_thread_entry_01\n");
    while (1) {
        // update modbus slave components into local modbus master register
        mbm_fsm_update(&g_sys, &mbm_dev_inst[MB_MASTER_1], MB_MASTER_1);
        rt_thread_delay(1000);
    }
}

//******************************保持寄存器回调函数**********************************
//函数定义: eMBErrorCode eMBMasterRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode
// eMode ) 描    述：保持寄存器相关的功能（读、连续读、写、连续写） 入口参数：pucRegBuffer :
//如果需要更新用户寄存器数值，这个缓冲区必须指向新的寄存器数值。
//                         如果协议栈想知道当前的数值，回调函数必须将当前值写入这个缓冲区
//					usAddress    : 寄存器的起始地址。
//					usNRegs      : 寄存器数量
//          eMode        : 如果该参数为eMBRegisterMode::MB_REG_WRITE，用户的应用数值将从pucRegBuffer中得到更新。
//                         如果该参数为eMBRegisterMode::MB_REG_READ，用户需要将当前的应用数据存储在pucRegBuffer中
//出口参数：eMBErrorCode : 这个函数将返回的错误码
//备    注：Editor：Armink 2013-11-25    Company: BXXJS
//**********************************************************************************
eMBErrorCode eMBMasterRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode, UCHAR ucMB_Number)
{
    extern sys_reg_st g_sys;
    eMBErrorCode      eStatus = MB_ENOERR;
    uint16_t          iRegIndex;
    uint16_t         *pusRegHoldingBuf;
    uint16_t          REG_HOLDING_START;
    uint16_t          REG_HOLDING_NREGS;
    uint16_t          usRegHoldStart;
    uint8_t           mbm_dest_addr, index;
    uint8_t           k;
    BOOL              Find_Flag = FALSE;

    // If mode is read,the master will wirte the received date to bufffer.
    if (eMode == MB_REG_WRITE) {
        return (MB_ENOERR);
    }
    eMode         = MB_REG_WRITE;
    mbm_dest_addr = ucMBMasterGetDestAddress(ucMB_Number) - 1;

    switch (ucMB_Number) {
        case MB_MASTER_0:
            pusRegHoldingBuf  = usMRegHoldBuf[mbm_dest_addr];
            REG_HOLDING_START = M_REG_HOLDING_START;
            REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
            usRegHoldStart    = usMRegHoldStart;
            index             = 0;

            usAddress--;  // FreeModbus功能函数中已经加1，为保证与缓冲区首地址一致，故减1
            if (((usAddress >= REG_HOLDING_START) && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) || ((mbm_dest_addr == MBM_DEV_IPM_ADDR))) {
                iRegIndex = usAddress - usRegHoldStart;
                switch (eMode) {
                        /* Pass current register values to the protocol stack. */
                    case MB_REG_READ:  //未使用
                        while (usNRegs > 0) {
                            *pucRegBuffer++ = (unsigned char)(pusRegHoldingBuf[iRegIndex] >> 8);
                            *pucRegBuffer++ = (unsigned char)(pusRegHoldingBuf[iRegIndex] & 0xFF);
                            iRegIndex++;
                            usNRegs--;
                        }
                        break;

                        /* Update current register values with new values from the
                         * protocol stack. */
                    case MB_REG_WRITE:
                        if (mbm_dest_addr == MBM_DEV_IPM_ADDR)  //地址数据更新
                        {
                            for (k = 0; k < mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].reg_rd_cnt; k++) {
                                if ((usAddress == mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].rd_pt[k].dev_reg_addr) &&
                                    (usNRegs == mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].rd_pt[k].NRegs)) {
                                    index     = k;
                                    Find_Flag = TRUE;
                                }
                            }
                            if ((index < mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].reg_rd_cnt) && (Find_Flag == TRUE)) {
                                iRegIndex = mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].rd_pt[index].J_Offset_Addr;
                                while (usNRegs > 0) {
                                    pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                                    pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                                    iRegIndex++;
                                    usNRegs--;
                                }
                            } else {
                                rt_kprintf("mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].reg_rd_cn_ERRO\n");
                            }
                        } else  //地址1-8数据更新
                        {
                            while (usNRegs > 0) {
                                pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                                pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                                iRegIndex++;
                                usNRegs--;
                            }
                        }
                        break;
                }
            } else {
                eStatus = MB_ENOREG;
            }
            break;
        case MB_MASTER_1:
            pusRegHoldingBuf  = usMRegHoldBuf_01[mbm_dest_addr];
            REG_HOLDING_START = M_REG_HOLDING_START_01;
            REG_HOLDING_NREGS = M_REG_HOLDING_NREGS_01;
            usRegHoldStart    = M_REG_HOLDING_START_01;
            index             = 0;

            usAddress--;  // FreeModbus功能函数中已经加1，为保证与缓冲区首地址一致，故减1
            if ((usAddress >= REG_HOLDING_START) && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) {
                for (k = 0; k < mbm_read_table_01[mbm_dest_addr].reg_rd_cnt; k++) {
                    if ((usAddress == mbm_read_table_01[mbm_dest_addr].rd_pt[k].dev_reg_addr) && (usNRegs == mbm_read_table_01[mbm_dest_addr].rd_pt[k].NRegs)) {
                        index     = k;
                        Find_Flag = TRUE;
                    }
                }

                if ((index < mbm_read_table_01[mbm_dest_addr].reg_rd_cnt) && (Find_Flag == TRUE)) {
                    iRegIndex = mbm_read_table_01[mbm_dest_addr].rd_pt[index].J_Offset_Addr;
                    while (usNRegs > 0) {
                        pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                        pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                        iRegIndex++;
                        usNRegs--;
                    }
                } else {
                    rt_kprintf("mbm_read_table[mbm_dest_addr - MB_MASTER_DISCRETE_OFFSET].reg_rd_cn_ERRO\n");
                }
            } else {
                eStatus = MB_ENOREG;
            }
            break;
        default:
            eStatus = MB_ENOREG;
            break;
    }
    return eStatus;
}

/**
  * @brief  update local modbus master register map with only variable device reg values
  * @param
            @mbm_dev_inst: modbus master device data struct.
  * @retval
            @arg 1: all device online
            @arg 0: not all device online
  */
static uint16_t mbm_reg_update(mbm_dev_st *mbm_dev_inst, UCHAR ucMB_Number)
{
    eMBMasterReqErrCode errorCode = MB_MRE_NO_ERR;
    uint16_t            dev_init_bitmap_reg;
    uint16_t            dev_update_bitmap_reg;

    uint16_t i, j;
    UCHAR    ucResult = 0;

    switch (ucMB_Number) {
        case MB_MASTER_0:
        {
            dev_init_bitmap_reg   = mbm_dev_inst->bitmap.init;
            dev_update_bitmap_reg = 0;

            for (i = 0; i < MB_MASTER_TOTAL_SLAVE_NUM; i++) {
                if (((dev_init_bitmap_reg >> i) & 0x0001) == 1) {
                    switch (i) {
                        case MBM_DEV_IPM_ADDR:
                        {
                            for (j = 0; j < mbm_read_table[i - MB_MASTER_DISCRETE_OFFSET].reg_rd_cnt; j++) {
                                errorCode = eMBMasterReqReadHoldingRegister((i + 1), mbm_read_table[i - MB_MASTER_DISCRETE_OFFSET].rd_pt[j].dev_reg_addr,
                                                                            mbm_read_table[i - MB_MASTER_DISCRETE_OFFSET].rd_pt[j].NRegs, MBM_RESPONSE_DELAY * 2, ucMB_Number);
                                if (errorCode == MB_MRE_NO_ERR) {
                                    dev_update_bitmap_reg |= (0x0001 << i);
                                    g_sys.status.mbm.Err_M.Err_Master0[i] = 0;
                                } else {
                                    if (g_sys.status.mbm.Err_M.Err_Master0[i] < 0xFF) {
                                        g_sys.status.mbm.Err_M.Err_Master0[i]++;
                                    }
                                }
                                rt_thread_delay(MBM_QUEST_DELAY * 2);
                            }
                            break;
                        }
                        default:
                            break;
                    }
                    if (g_sys.status.mbm.Err_M.Err_Master0[i] < MBM_ERR_NUM)  //减少报错
                    {
                        dev_update_bitmap_reg |= (0x0001 << i);
                    }
                }
            }
            // rt_kprintf("dev_update_bitmap_reg=%d,dev_init_bitmap_reg= %d,Err_Master0= %d\n", dev_update_bitmap_reg, dev_init_bitmap_reg, g_sys.status.mbm.Err_M.Err_Master0[0]);
            mbm_dev_inst->bitmap.update = dev_update_bitmap_reg;
            if (dev_update_bitmap_reg == mbm_dev_inst->bitmap.init) {
                mbm_dev_inst->timeout.update = 0;
                mbm_dev_inst->errcnt.update  = 0;
                ucResult                     = 1;
            } else {
                mbm_dev_inst->timeout.update++;
                mbm_dev_inst->errcnt.update++;

                ucResult = 0;
            }
            break;
        }
        case MB_MASTER_1:
        {
            dev_init_bitmap_reg   = mbm_dev_inst->bitmap.init;
            dev_update_bitmap_reg = 0;

            for (i = 0; i < MB_MASTER_SLAVE_NUM_01; i++) {
                if (((dev_init_bitmap_reg >> i) & 0x0001) == 1) {
                    switch (i) {
                        case MBM_DEV_AC_ADDR:
                            for (j = 0; j < mbm_read_table_01[i].reg_rd_cnt; j++) {
                                errorCode =
                                    eMBMasterReqReadInputRegister((i + 1), mbm_read_table_01[i].rd_pt[j].dev_reg_addr, mbm_read_table_01[i].rd_pt[j].NRegs, MBM_RESPONSE_DELAY * 2, ucMB_Number);
                                if (errorCode == MB_MRE_NO_ERR) {
                                    dev_update_bitmap_reg |= (0x0001 << i);
                                    g_sys.status.mbm.Err_M.Err_Master1[i] = 0;
                                } else {
                                    if (g_sys.status.mbm.Err_M.Err_Master1[i] < 0xFF) {
                                        g_sys.status.mbm.Err_M.Err_Master1[i]++;
                                    }
                                }
                                rt_thread_delay(MBM_QUEST_DELAY * 2);
                            }
                            errorCode = eMBMasterReqReadDiscreteInputs(MBM_DEV_AC_ADDR + 1, M_REG_COLS_START_01, M_REG_COLS_NREGS_01, MBM_RESPONSE_DELAY * 2, ucMB_Number);
                            rt_thread_delay(MBM_QUEST_DELAY * 2);
                            break;
                        default:
                            break;
                    }
                    if (g_sys.status.mbm.Err_M.Err_Master1[i] < MBM_ERR_NUM)  //减少报错
                    {
                        dev_update_bitmap_reg |= (0x0001 << i);
                    }
                }
            }
            mbm_dev_inst->bitmap.update = dev_update_bitmap_reg;
            if (dev_update_bitmap_reg == mbm_dev_inst->bitmap.init) {
                mbm_dev_inst->timeout.update = 0;
                ucResult                     = 1;
            } else {
                mbm_dev_inst->timeout.update++;
                mbm_dev_inst->errcnt.update++;
                //                if (mbm_dev_inst->timeout.update >= MBM_UPDATE_TIMEOUT_THRESHOLD)
                //                {
                //                    mbm_dev_inst->bitmap.init = dev_update_bitmap_reg;
                //                }
                ucResult = 0;
            }
            break;
        }
        default:
            ucResult = 0;
            break;
    }
    return ucResult;
}

static void mbm_send_fun(mbm_data_st *send_data, UCHAR ucMB_Number)
{
    eMBMasterReqErrCode errorCode = MB_MRE_NO_ERR;
    // Alair,20161226
    switch (send_data->mbm_WriteType) {
        case MB_WRITE_SINGLE:  // 06 写单个寄存器
        {
            errorCode = eMBMasterReqWriteHoldingRegister(send_data->mbm_addr, send_data->reg_addr, send_data->reg_value, MBM_RESPONSE_DELAY, ucMB_Number);
            if (errorCode != MB_MRE_NO_ERR) {
                rt_kprintf("%d,mbm_send_fun erro= %d\n", ucMB_Number, errorCode);
            }
            break;
        }
        case MB_WRITE_MULITE:  // 10 写多个寄存器
        {
            errorCode = eMBMasterReqWriteMultipleHoldingRegister(send_data->mbm_addr, send_data->reg_addr, send_data->mbm_NRegs, &(send_data->reg_value), MBM_RESPONSE_DELAY, ucMB_Number);
            if (errorCode != MB_MRE_NO_ERR) {
                rt_kprintf("%d,mbm_send_fun erro= %d\n", ucMB_Number, errorCode);
            }
            break;
        }
        case MB_WR_SINGLE_BIT:  // 05 写单个位
        {
            if (send_data->reg_value) {
                errorCode = eMBMasterReqWriteCoil(send_data->mbm_addr, send_data->reg_addr, 0xff00, MBM_RESPONSE_DELAY, ucMB_Number);
            } else {
                errorCode = eMBMasterReqWriteCoil(send_data->mbm_addr, send_data->reg_addr, 0x0000, MBM_RESPONSE_DELAY, ucMB_Number);
            }

            if (errorCode != MB_MRE_NO_ERR) {
                rt_kprintf("%d,eMBMasterReqWriteCoil erro= %d\n", ucMB_Number, errorCode);
            }
            break;
        }
        default:
            break;
    }
    rt_thread_delay(MBM_QUEST_DELAY);
}

/**
 * @brief  update local modbus master register map with only variable device reg values(ie. reg addr after 20)
 * @param  mbm_dev_inst: modbus master device data struct.
 * @retval none
 */
static void mbm_fsm_update(sys_reg_st *gds_ptr, mbm_dev_st *mbm_dev_inst, UCHAR ucMB_Number)
{
    uint16_t    mbm_fsm_cstate;
    uint8_t     i, len;
    mbm_data_st send_data;

    mbm_fsm_cstate = mbm_dev_inst->mbm_fsm;
    switch (ucMB_Number) {
        case MB_MASTER_0:
            mbm_dev_inst->bitmap.init = gds_ptr->config.dev_mask.mb_comp[COM_IPM];
            break;
        case MB_MASTER_1:
            mbm_dev_inst->bitmap.init = 1;//gds_ptr->config.dev_mask.mb_comp[COM_AC];
            break;
        default:
            break;
    }
    switch (mbm_fsm_cstate) {
        case (MBM_FSM_IDLE):
        {
            mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
            break;
        }
        case (MBM_FSM_SYNC):
        {
            mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
            break;
        }
        case (MBM_FSM_UPDATE):
        {
            if (ucMB_Number == MB_MASTER_0) {
                mbm_reg_update(mbm_dev_inst, ucMB_Number);
                if ((mbm_dev_inst->timeout.update >= MBM_UPDATE_TIMEOUT_THRESHOLD) || (mbm_dev_inst->bitmap.init != mbm_dev_inst->bitmap.update))  // if update err count timeout, swich to sync state
                {
                    mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
                } else if (is_fifo8_empty(&mbm_data_fifo) == 0) {
                    mbm_dev_inst->mbm_fsm = MBM_FSM_SEND;
                } else {
                    mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
                }
            } else {
                mbm_reg_update(mbm_dev_inst, ucMB_Number);
                if (ucMB_Number == MB_MASTER_1) {
                    if (is_fifo8_empty(&mbm_data_fifo_01) == 0) {
                        mbm_dev_inst->mbm_fsm = MBM_FSM_SEND;
                    } else {
                        mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
                    }
                }
            }
            break;
        }
        case MBM_FSM_SEND:
        {
            switch (ucMB_Number) {
                case MB_MASTER_0:
                    len = get_fifo8_length(&mbm_data_fifo);
                    for (i = 0; i < len; i++) {
                        if (fifo8_pop(&mbm_data_fifo, (uint8_t *)&send_data) == 1) {
                            mbm_send_fun(&send_data, ucMB_Number);
                        }
                    }
                    break;
                case MB_MASTER_1:
                    len = get_fifo8_length(&mbm_data_fifo_01);
                    rt_kprintf("len=%d", len);
                    for (i = 0; i < len; i++) {
                        if (fifo8_pop(&mbm_data_fifo_01, (uint8_t *)&send_data) == 1) {
                            mbm_send_fun(&send_data, ucMB_Number);
                        }
                    }
                    break;
                default:
                    break;
            }
            mbm_dev_inst->mbm_fsm = MBM_FSM_UPDATE;
            break;
        }
        default:
        {
            mbm_dev_inst->mbm_fsm = MBM_FSM_IDLE;
            break;
        }
    }
    if (ucMB_Number == MB_MASTER_0) {
        //通信不畅，不每次更新，偶尔冲突时数据不刷新
        if ((mbm_dev_inst->errcnt.update == 0) || (mbm_dev_inst->errcnt.update >= 5) || (mbm_dev_inst->bitmap.init == mbm_dev_inst->bitmap.update)) {
            gds_ptr->status.status_remap[IPM_COM_STS_REG_NO] = mbm_dev_inst->bitmap.update;
        }
        // rt_kprintf("dev_update_bitmap_reg=%d,dev_init_bitmap_reg= %d,COM_IPM= %x,IPM_COM_STS_REG_NO= %x\n", mbm_dev_inst->bitmap.update, mbm_dev_inst->bitmap.init,
        //            gds_ptr->config.dev_mask.mb_comp[COM_IPM], gds_ptr->status.status_remap[IPM_COM_STS_REG_NO]);
    } else if (ucMB_Number == MB_MASTER_1) {
        if ((mbm_dev_inst->errcnt.update == 0) || (mbm_dev_inst->errcnt.update >= 5) || (mbm_dev_inst->bitmap.init == mbm_dev_inst->bitmap.update)) {
            gds_ptr->status.status_remap[AC_COM_STS_REG_NO] = mbm_dev_inst->bitmap.update;
        }
    }
}

/**
 * @brief  modbus local data structure initialization
 * @param  mbm_dev_inst: modbus master device data struct.
 * @retval none
 */
static void mbm_fsm_init(mbm_dev_st *mbm_dev_inst)
{
    mbm_dev_inst->bitmap.poll         = 0;
    mbm_dev_inst->bitmap.init         = 0;
    mbm_dev_inst->bitmap.update       = 0;
    mbm_dev_inst->timeout.poll        = 0;
    mbm_dev_inst->timeout.init        = 0;
    mbm_dev_inst->timeout.update      = 0;
    mbm_dev_inst->errcnt.poll         = 0;
    mbm_dev_inst->errcnt.init         = 0;
    mbm_dev_inst->errcnt.update       = 0;
    mbm_dev_inst->mbm_fsm             = MBM_FSM_IDLE;
    g_sys.status.mbm.Err_M.Err_Enable = 0x00;
}

/**
 * @brief  modbus module interface, update global register with designated local modbus register values
 * @param  gds_ptr		global register struct pointer
 * @retval none
 **/
void mbm_sts_update(sys_reg_st *gds_ptr, UCHAR ucMB_Number)
{
    uint16_t    mbm_dev_update_bitmap;
    uint16_t    mbm_dev_init_bitmap;
    uint8_t     j, k, h;
    mbm_data_st mbm_send_data;

    mbm_dev_init_bitmap = mbm_dev_inst[ucMB_Number].bitmap.init;
    // get modbus update bitmap which could be used to determin which glabal regsiter to update
    mbm_dev_update_bitmap = mbm_dev_inst[ucMB_Number].bitmap.update;
    // rt_kprintf("MB_MASTER_0 = %x,MB_MASTER_1 = %x\n", mbm_dev_inst[MB_MASTER_0].bitmap.update,
    //            mbm_dev_inst[MB_MASTER_1].bitmap.update);
    switch (ucMB_Number) {
        case MB_MASTER_0:
            //  IPM　information update
            for (j = 0; j < MBM_DISCRETE_DEV_CNT; j++)  // IPM,PDU特殊读取
            {
                if (((mbm_dev_init_bitmap >> mbm_read_table[j].mbm_addr) & 0x0001) != 0) {  // copy modbus master device register to global register, power daq
                    if (((mbm_dev_update_bitmap >> mbm_read_table[j].mbm_addr) & 0x0001) != 0) {
                        for (k = 0; k < mbm_read_table[j].reg_rd_cnt; k++) {
                            for (h = 0; h < mbm_read_table[j].rd_pt[k].NRegs; h++) {
                                static rt_int8_t DPT = 0, CPT = 0, DPQ = 0, PQ = 0;
                                *(mbm_read_table[j].rd_pt[k].data_ptr + h) = usMRegHoldBuf[mbm_read_table[j].mbm_addr][mbm_read_table[j].rd_pt[k].J_Offset_Addr + h];
                                // AMC
                                //特殊数据处理
                                if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.F) {
                                    g_sys.status.mbm.IPM.IPM.F *= 0.1;  //保留一位小数
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ux[0]) {
                                    g_sys.status.mbm.IPM.IPM.Ux[0] = g_sys.status.mbm.IPM.IPM.Ux[0] * pow(10, (DPT - 3));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ux[1]) {
                                    g_sys.status.mbm.IPM.IPM.Ux[1] = g_sys.status.mbm.IPM.IPM.Ux[1] * pow(10, (DPT - 3));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ux[2]) {
                                    g_sys.status.mbm.IPM.IPM.Ux[2] = g_sys.status.mbm.IPM.IPM.Ux[2] * pow(10, (DPT - 3));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ix[0]) {
                                    g_sys.status.mbm.IPM.IPM.Ix[0] = g_sys.status.mbm.IPM.IPM.Ix[0] * pow(10, (CPT - 4));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ix[1]) {
                                    g_sys.status.mbm.IPM.IPM.Ix[1] = g_sys.status.mbm.IPM.IPM.Ix[1] * pow(10, (CPT - 4));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Ix[2]) {
                                    g_sys.status.mbm.IPM.IPM.Ix[2] = g_sys.status.mbm.IPM.IPM.Ix[2] * pow(10, (CPT - 4));
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Px[0]) {
                                    g_sys.status.mbm.IPM.IPM.Px[0] = g_sys.status.mbm.IPM.IPM.Px[0] * pow(10, (DPQ - 4));
                                    if (PQ & 0x01)
                                        g_sys.status.mbm.IPM.IPM.Px[0] = -g_sys.status.mbm.IPM.IPM.Px[0];
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Px[1]) {
                                    g_sys.status.mbm.IPM.IPM.Px[1] = g_sys.status.mbm.IPM.IPM.Px[1] * pow(10, (DPQ - 4));
                                    if (PQ & 0x02)
                                        g_sys.status.mbm.IPM.IPM.Px[1] = -g_sys.status.mbm.IPM.IPM.Px[1];
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Px[2]) {
                                    g_sys.status.mbm.IPM.IPM.Px[2] = g_sys.status.mbm.IPM.IPM.Px[2] * pow(10, (DPQ - 4));
                                    if (PQ & 0x04)
                                        g_sys.status.mbm.IPM.IPM.Px[2] = -g_sys.status.mbm.IPM.IPM.Px[2];
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.IPM.Psum) {
                                    g_sys.status.mbm.IPM.IPM.Psum = g_sys.status.mbm.IPM.IPM.Psum * pow(10, (DPQ - 4));
                                    if (PQ & 0x08)
                                        g_sys.status.mbm.IPM.IPM.Psum = -g_sys.status.mbm.IPM.IPM.Psum;
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.CT) {
                                    rt_uint32_t Val_t = 0, Val_s = 0;

                                    Val_t                       = (g_sys.status.mbm.IPM.P_Wh_H << 16) | g_sys.status.mbm.IPM.P_Wh_L;
                                    Val_s                       = Val_t * g_sys.status.mbm.IPM.PT * g_sys.status.mbm.IPM.CT / 10;
                                    g_sys.status.mbm.IPM.P_Wh_H = Val_s & 0xffff;
                                    g_sys.status.mbm.IPM.P_Wh_L = Val_s >> 16;
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.DP_CT) {
                                    DPT = g_sys.status.mbm.IPM.DP_CT >> 8;
                                    CPT = g_sys.status.mbm.IPM.DP_CT & 0xff;
                                } else if ((mbm_read_table[j].rd_pt[k].data_ptr + h) == &g_sys.status.mbm.IPM.DPQ) {
                                    DPQ = g_sys.status.mbm.IPM.DPQ >> 8;
                                }
                            }
                        }

                        // test
                        // rt_kprintf("IPM.Ux[0]=%d,IPM.Ux[2]=%d,P_Wh_L=%d\n", g_sys.status.mbm.IPM.IPM.Ux[0],
                        //            g_sys.status.mbm.IPM.IPM.Ux[2], g_sys.status.mbm.IPM.P_Wh_L);
                    } else  // if device is not initialized, all date reset to 0
                    {
                        for (k = 0; k < mbm_read_table[j].reg_rd_cnt; k++) {
                            for (h = 0; h < mbm_read_table[j].rd_pt[k].NRegs; h++) {
                                *(mbm_read_table[j].rd_pt[k].data_ptr + h) = 0;
                            }
                        }
                    }
                }
            }
            break;
        case MB_MASTER_1:  // AC
            for (j = 0; j < MBM_DISCRETE_DEV_CNT_1; j++) {
                if (((mbm_dev_init_bitmap >> mbm_read_table_01[j].mbm_addr) & 0x0001) != 0) {  // copy modbus master device register to global register, power daq
                    if (((mbm_dev_update_bitmap >> mbm_read_table_01[j].mbm_addr) & 0x0001) != 0) {
                        for (k = 0; k < mbm_read_table_01[j].reg_rd_cnt; k++) {
                            for (h = 0; h < mbm_read_table_01[j].rd_pt[k].NRegs; h++) {
                                *(mbm_read_table_01[j].rd_pt[k].data_ptr + h) = usMRegHoldBuf_01[mbm_read_table_01[j].mbm_addr][mbm_read_table_01[j].rd_pt[k].J_Offset_Addr + h];
                                if (firstFlag != 0x07ff) {
                                    uint8_t ii;
                                    for (ii = 0; ii < AC_WRITE_CNT; ii++) {
                                        if (((mbm_read_table_01[j].rd_pt[k].data_ptr + h) == AC_write_reg[ii].status_ptr) && (!(firstFlag & (1 << ii)))) {
                                            firstFlag |= (1 << ii);
                                            write_reg_map(AC_write_reg[ii].Conf_addr, *(AC_write_reg[ii].status_ptr));
                                        }
                                    }
                                }
                            }
                        }
                        if (mbm_read_table_01[j].reg_w_cnt != 0) {
                            for (k = 0; k < mbm_read_table_01[j].reg_w_cnt; k++) {
                                if (*(mbm_read_table_01[j].w_pt[k].conf_Flag) == FALSE) {
                                    if ((*(mbm_read_table_01[j].w_pt[k].conf_ptr) != *(mbm_read_table_01[j].w_pt[k].status_ptr))) {
                                        write_reg_map(mbm_read_table_01[j].w_pt[k].Conf_addr, *(mbm_read_table_01[j].w_pt[k].status_ptr));
                                    }
                                } else {
                                    if ((firstFlag & (1 << k)) == 0) {
                                        return;
                                    }
                                    if (*(mbm_read_table_01[j].w_pt[k].conf_ptr) != *(mbm_read_table_01[j].w_pt[k].status_ptr)) {
                                        mbm_send_data.mbm_addr      = mbm_read_table_01[j].mbm_addr + 1;
                                        mbm_send_data.reg_addr      = mbm_read_table_01[j].w_pt[k].dev_reg_addr;
                                        mbm_send_data.reg_value     = *(mbm_read_table_01[j].w_pt[k].conf_ptr);
                                        mbm_send_data.mbm_NRegs     = 1;
                                        mbm_send_data.mbm_WriteType = mbm_read_table_01[j].w_pt[k].funCode;
                                        //压入FIFO;
                                        if (fifo8_push(&mbm_data_fifo_01, (uint8_t *)&mbm_send_data) == 0) {
                                            rt_kprintf("\n mbm_read_table_01 ERRO\n");
                                        }
                                    } else {
                                        *(mbm_read_table_01[j].w_pt[k].conf_Flag) = FALSE;
                                    }
                                }
                            }
                        }
                    } else  // if device is not initialized, all date reset to 0
                    {
                        for (k = 0; k < mbm_read_table_01[j].reg_rd_cnt; k++) {
                            *(mbm_read_table_01[j].rd_pt[k].data_ptr) = 0;
                        }
                    }
                }
            }
            break;
        default:
            break;
    }
}
eMBErrorCode eMBMasterRegDiscreteCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNDiscrete, UCHAR ucMB_Number)
{
    // uint8_t mbm_dest_addr;
    uint8_t cache = 0, index = 0, Num;
    // mbm_dest_addr = ucMBMasterGetDestAddress(ucMB_Number) - 1;
    usAddress--;  // FreeModbus功能函数中已经加1，为保证与缓冲区首地址一致，故减1
    switch (ucMB_Number) {
        case MB_MASTER_1:  // AC
            // rt_kprintf("eMBMasterRegDiscreteCB:%d\r\n", mbm_dest_addr);
            // rt_kprintf("\t\tucMB_Number:%d\r\n", ucMB_Number);
            // rt_kprintf("\t\tusAddress:%d\r\n", usAddress);
            // rt_kprintf("\t\tusNDiscrete:%d\r\n", usNDiscrete);
            // rt_kprintf("\t\tpucRegBuffer:");

            do {
                if (usNDiscrete > 8)
                    Num = 8;
                else
                    Num = usNDiscrete;
                cache = xMBUtilGetBits(pucRegBuffer, index, Num);
                xMBUtilSetBits((uint8_t *)g_sys.status.mbm.AC.ACFUN02H, usAddress - M_REG_COLS_START_01 + index, Num, cache);
                usNDiscrete -= Num;
                index += Num;
                // rt_kprintf("%02x ", cache);
            } while (usNDiscrete > 0);

            // rt_kprintf("\r\n");
            AC_PowerON = (g_sys.status.mbm.AC.ACFUN02H[2] & (1 << 9));

            if (!(firstFlag & (1 << 10))) {
                firstFlag |= (1 << 10);
                write_reg_map(mbm_read_table_01[0].w_pt[10].Conf_addr, *(mbm_read_table_01[0].w_pt[10].status_ptr));
            }

            break;
        default:
            break;
    }
    return MB_ENOERR;
}
eMBErrorCode eMBMasterRegCoilsCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode, UCHAR ucMB_Number)
{
    if (eMode == MB_REG_WRITE)
        return MB_ENOERR;
    return MB_ENOERR;
}
